#include "upgrade_diagnosis.h"

#include <algorithm>
#include <future>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <iomanip>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <minizip-ng/mz_zip.h>
#include <minizip-ng/mz_strm.h>
#include <minizip-ng/mz_zip_rw.h>
#include <dirent.h>

#include "base_file_util.h"
#include "base_utils.h"
#include "base_string.h"
#include "base_log.h"
#include "common_shell.h"

#include "upgrade.h"

// 添加MZ_OK定义
#define MZ_OK 0

namespace El {
namespace Upgrade {

UpgradeDiagnosis &UpgradeDiagnosis::GetInstance()
{
    static UpgradeDiagnosis instance;
    return instance;
}

bool UpgradeDiagnosis::Start()
{
    Common::Shell::GetInstance().RegisterCommand("upgrade",
                                                 std::bind(&UpgradeDiagnosis::Upgrade, this, std::placeholders::_1));
    return true;
}

void PrintHexDiff(const uint8_t *data1, const uint8_t *data2, size_t offset, size_t length)
{
    printf("Difference at offset 0x%08zx:\n", offset);
    printf("MTD     : ");
    for (size_t i = 0; i < length && i < 16; i++) {
        printf("%02X ", data1[i]);
    }
    printf("\nPackage : ");
    for (size_t i = 0; i < length && i < 16; i++) {
        printf("%02X ", data2[i]);
    }
    printf("\n");
}

std::string UpgradeDiagnosis::FindUpgradeFile()
{
    std::string upgrade_file;
    std::vector<std::pair<std::string, time_t>> hex_files;

    // 首先查找/home/目录
    DIR *home_dir = opendir("/home/");
    if (home_dir != nullptr) {
        struct dirent *entry;
        while ((entry = readdir(home_dir)) != nullptr) {
            std::string filename(entry->d_name);
            if (filename.length() >= 4 && filename.substr(filename.length() - 4) == ".hex") {
                std::string full_path = "/home/" + filename;
                struct stat st;
                if (stat(full_path.c_str(), &st) == 0) {
                    hex_files.push_back({full_path, st.st_mtime});
                }
            }
        }
        closedir(home_dir);
    }

    // 如果/home/目录下没有找到hex文件，则查找/mnt/udisk/目录
    if (hex_files.empty()) {
        DIR *udisk_dir = opendir("/mnt/udisk/");
        if (udisk_dir != nullptr) {
            struct dirent *entry;
            while ((entry = readdir(udisk_dir)) != nullptr) {
                std::string filename(entry->d_name);
                if (filename.length() >= 4 && filename.substr(filename.length() - 4) == ".hex") {
                    std::string full_path = "/mnt/udisk/" + filename;
                    struct stat st;
                    if (stat(full_path.c_str(), &st) == 0) {
                        hex_files.push_back({full_path, st.st_mtime});
                    }
                }
            }
            closedir(udisk_dir);
        }
    }

    if (hex_files.empty()) {
        LOG_ERROR("No .hex file found in /home/ or /mnt/udisk/");
    } else {
        // 按照时间戳排序，选择最新的文件
        std::sort(hex_files.begin(), hex_files.end(), [](const auto &a, const auto &b) { return a.second > b.second; });
        upgrade_file = hex_files[0].first;
        LOG_INFO("Found newest upgrade file: {}", upgrade_file);
    }

    return upgrade_file;
}

void UpgradeDiagnosis::Upgrade(const std::string &args)
{
    std::vector<std::string> vec_args;
    Base::Split(args, " ", vec_args);
    if (vec_args.empty()) {
        LOG_ERROR("Invalid args: empty");
        return;
    }

    // 诊断命令
    if (vec_args[0] == "upgrade") {
        std::string upgrade_file = FindUpgradeFile();
        if (upgrade_file.empty()) {
            LOG_ERROR("No upgrade file found");
            return;
        }
        LOG_INFO("Starting upgrade with file: {}", upgrade_file);

        Upgrade::GetInstance().PrepareUpgrade();
        // 读取文件内容并调用Append
        std::ifstream file(upgrade_file, std::ios::binary);
        if (!file) {
            LOG_ERROR("Cannot open upgrade file");
            return;
        }

        std::vector<uint8_t> buffer(4096);
        while (file.good()) {
            file.read(reinterpret_cast<char *>(buffer.data()), buffer.size());
            if (file.gcount() > 0) {
                if (!Upgrade::GetInstance().Append(buffer.data(), file.gcount())) {
                    LOG_ERROR("Failed to append upgrade data");
                    return;
                }
            }
        }

        if (!Upgrade::GetInstance().StartUpgrade()) {
            LOG_ERROR("Upgrade failed");
            return;
        }
        LOG_INFO("Upgrade completed successfully");
    } else {
        LOG_ERROR("Invalid command: {}", vec_args[0]);
    }
}

} // namespace Upgrade
} // namespace El